package com.xinsoft.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.xinsoft.common.exception.BDException;
import com.xinsoft.entity.dto.*;
import com.xinsoft.entity.po.SysDept;
import com.xinsoft.entity.po.SysRole;
import com.xinsoft.entity.po.SysUser;
import com.xinsoft.entity.po.SysUserRole;
import com.xinsoft.entity.vo.SysUserVo;
import com.xinsoft.mapper.SysUserMapper;
import com.xinsoft.service.*;
import com.xinsoft.utils.ExcelImportUtils;
import com.xinsoft.utils.ExcelUtils;
import com.xinsoft.validator.ValidatorUtils;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
* @author xuhb
* @description 针对表【sys_user(用户表)】的数据库操作Service实现
* @createDate 2023-04-10 11:34:27
*/
@Slf4j
@Service
public class  SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private SysUserRoleService sysUserRoleService;
    @Resource
    private SysRoleService sysRoleService;
    @Resource
    private SysDeptService sysDeptService;

    @Resource
    private SysFileHisService sysFileHisService;



    @Transactional(rollbackFor = Exception.class)
    @Override
    @Synchronized
    public SysUser addSysUser(SysUserDTO sysUserDTO){

        //判断用户名是否重复
        QueryWrapper<SysUser> sysUserQuery = new QueryWrapper<>();
        String userName = sysUserDTO.getUsername();
        sysUserQuery.eq("username",userName);
        List users = this.list(sysUserQuery);

        if(CollectionUtil.isNotEmpty(users)){
            throw new BDException("操作失败，用户名重复");
        }
        SysUser user = new SysUser();
        BeanUtils.copyProperties(sysUserDTO,user);
        //保存
        user.setPassword(passwordEncoder.encode(sysUserDTO.getPassword()));

        this.save(user);

        //保存用户角色
        if(CollectionUtil.isNotEmpty(sysUserDTO.getRoleIds())){
            List<SysUserRole> userRoleList = new ArrayList();
            for (Integer roleId : sysUserDTO.getRoleIds()) {
                SysUserRole userRole = new SysUserRole();
                userRole.setRoleId(roleId);
                userRole.setUserId(user.getId());
                userRoleList.add(userRole);
            }
            sysUserRoleService.saveBatch(userRoleList);
        }

        return user;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    @Synchronized
    public SysUser editSysUser(SysUserDTO sysUserDTO){

        SysUser user = getById(sysUserDTO.getId());
        if (user== null) {
            throw new BDException("操作失败，用户不存在");
        }
        BeanUtils.copyProperties(sysUserDTO,user);
        user.setId(sysUserDTO.getId());
        //保存
        this.updateById(user);

        QueryWrapper userRoleQuery = new QueryWrapper();
        userRoleQuery.eq("user_id",sysUserDTO.getId());
        sysUserRoleService.remove(userRoleQuery);

        //保存用户角色
        if(CollectionUtil.isNotEmpty(sysUserDTO.getRoleIds())){
            List<SysUserRole> userRoleList = new ArrayList();
            for (Integer roleId : sysUserDTO.getRoleIds()) {
                SysUserRole userRole = new SysUserRole();
                userRole.setRoleId(roleId);
                userRole.setUserId(user.getId());
                userRoleList.add(userRole);
            }
            sysUserRoleService.saveBatch(userRoleList);
        }

        return user;
    }


    @Override
    @Synchronized
    @Transactional(rollbackFor = Exception.class)
    public void del(List<Integer> ids) {

        QueryWrapper<SysUser> sysUserQuery = new QueryWrapper<>();
        sysUserQuery.in("id",ids);
        sysUserQuery.eq("status",1);//启用
        List<SysUser> users = this.list(sysUserQuery);

        //判断是否已启用
        if(CollectionUtil.isNotEmpty(users)){
            throw new BDException("操作失败，"+users.get(0).getRealName()+"已启用无法删除！");
        }
        // 删除
        removeByIds(ids);

        // 删除关系表
        QueryWrapper userRoleQuery = new QueryWrapper();
        userRoleQuery.in("user_id",ids);
        sysUserRoleService.remove(userRoleQuery);
    }

    @Override
    public SysUserDTO getSysUser(Integer id){
        SysUser user = this.getById(id);
        SysUserDTO sysUserDTO= new SysUserDTO();
        BeanUtils.copyProperties(user,sysUserDTO);
        sysUserDTO.setId(user.getId());
        // 根据用户id获取角色ids
        List<SysRole> roles = sysRoleService.getRoleListByUserId(id);
        if(CollectionUtil.isNotEmpty(roles)){
           List<Integer> roleIds =  roles.stream().map(SysRole::getId).collect(Collectors.toList());
            sysUserDTO.setRoleIds(roleIds);
        }

        return sysUserDTO;
    }


    @Override
    public SysUser getSysUserByUsername(String username){

        QueryWrapper<SysUser> sysUserQuery = new QueryWrapper<>();
        sysUserQuery.eq("username",username);
        SysUser users = this.getOne(sysUserQuery);

        return users;
    }


    @Override
    @Synchronized
    public void resetPassWord(SysUserChangePasswordDTO sysUserChangePasswordDTO) {

        //修改密码
        SysUser user = new SysUser();
        user.setId(sysUserChangePasswordDTO.getId());
        user.setPassword(passwordEncoder.encode(sysUserChangePasswordDTO.getPassword()));
        updateById(user);
    }

    @Override
    @Synchronized
    public void enable(Integer id) {

        SysUser user = this.getById(id);
        if(user==null){
            throw new BDException("用户不存在！");
        }
        if(Objects.equals(user.getStatus(),1)){
            throw new BDException("操作失败，用户已经被启用");
        }
        user = new SysUser();
        user.setId(id);
        user.setStatus(1);//启用
        updateById(user);

    }

    @Override
    @Synchronized
    public void disable(Integer id) {
        SysUser user = this.getById(id);
        if(user==null){
            throw new BDException("用户不存在！");
        }
        if(Objects.equals(user.getStatus(),0)){
            throw new BDException("操作失败，用户已经被禁用");
        }
        user.setStatus(0);//禁用
        updateById(user);
    }

    @Override
    public IPage<SysUserVo> findPageListByParam(SysUserPageParam param) {
        //分页
        Page<SysUserVo> page = new Page<SysUserVo>(param.getCurrentPage(), param.getPageSize());
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        //查询条件
        queryWrapper
                .eq(StringUtils.isNotEmpty(param.getUsername()),"username",param.getUsername())
                .like(StringUtils.isNotEmpty(param.getUserRealName()),"real_name",param.getUserRealName())
                .eq(param.getDeptId()!=null,"dept_id",param.getDeptId())
                .eq(param.getStatus()!=null,"status",param.getStatus())
                .gt("id",0)
                .eq("do_delete",0)
                .orderByDesc("status")
                .orderByDesc("create_time");
        IPage<SysUserVo> applicationPageList = this.baseMapper.selectPageInfo(page, queryWrapper,param.getRoleId());

        //返回值
        return applicationPageList;
    }

    @Override
    public List<SysUserDTO> findListByParam(SysUserPageParam param) {
        //分页
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        //查询条件
        queryWrapper
                .eq(StringUtils.isNotEmpty(param.getUsername()),"username",param.getUsername())
                .like(StringUtils.isNotEmpty(param.getUserRealName()),"real_name",param.getUserRealName())
                .eq(param.getDeptId()!=null,"dept_id",param.getDeptId())
                .eq(param.getStatus()!=null,"status",param.getStatus())
                .eq("do_delete",0)
                .orderByDesc("status")
                .orderByDesc("create_time");
        List<SysUserDTO> applicationPageList = this.baseMapper.selectListInfo(queryWrapper,param.getRoleId());

        //返回值
        return applicationPageList;
    }

    @Override
    public void insertOrUpdateBatch(List<SysUser> sysUserList) {
        baseMapper.insertOrUpdateBatch(sysUserList);
    }

    @Override
    public void importData(MultipartFile multipartFile) throws IOException {

        //判断传进的表格后缀名：返回错误信息
        String name = multipartFile.getOriginalFilename();
        int splitIndex = name.lastIndexOf(".");
        String fileType = name.substring(splitIndex + 1);//doc、xls等
        if (!"xlsx".equals(fileType)) {
            throw new BDException("文件格式错误(.xlsx)");
        }
        InputStream in = multipartFile.getInputStream();
        Workbook wb = WorkbookFactory.create(in);
        //获取excel中数据
        Sheet sheet = wb.getSheet("用户");
        if (sheet == null) {
            throw new BDException("导入失败，用正确的模板导入");
        }

        //获取所有行数
        int rows = sheet.getPhysicalNumberOfRows();
        if (rows <= 1) {
            throw new BDException("excel内容不完整");
        }
        Row row1 = sheet.getRow(0);

        //处理标题行
        Map<String, Integer> titleMap = Maps.newHashMap();
        for (int i = 0; i < row1.getPhysicalNumberOfCells(); i++) {
            titleMap.put(ExcelImportUtils.getCellValue(row1.getCell(i)), i);
        }
        Boolean isSuccess = includeCustomInfo(titleMap);
        if (!isSuccess) {
            throw new BDException("表头字段缺少必须项");
        }

        //主表数据处理
        List<SysUser> users = new ArrayList<>();
        StringBuilder message = new StringBuilder();
        for (int i = 1; i < rows; i++) {
            SysUser sysUser = new SysUser();
            Row row = sheet.getRow(i);
            //为null说明遇到空行，那么导入到此行结束
            if (row == null) {
                break;
            }
            //解析行
            String userName =
                    ExcelImportUtils.getCellValue(row.getCell(titleMap.get("*用户名")));
            if (StringUtils.isNotBlank(userName)) {
                if (userName == null) {
                    message.append("第" + (i + 1) + "行用户名不能为空；");
                } else {
                    sysUser.setUsername(userName);
                }
            }

            String realName = ExcelImportUtils.getCellValue(row.getCell(titleMap.get("*真实姓名")));
            if (StringUtils.isBlank(realName)) {
                message.append("第" + (i + 1) + "行真实姓名不能为空；");
            } else {
                sysUser.setRealName(realName);
            }

            String userPassword = ExcelImportUtils.getCellValue(row.getCell(titleMap.get("密码")));
            if (StringUtils.isBlank(userPassword)) {
                message.append("第" + (i + 1) + "行密码不能为空；");
            } else {
                sysUser.setPassword(userPassword);
            }

            if (message.length() == 0) {
                users.add(sysUser);
            }

        }
        if (message.length() > 0) {
            throw new BDException(message.toString());
        }
        //保存
        for (SysUser sysUser : users) {
            SysUserDTO sysUserDTO = new SysUserDTO();
            BeanUtils.copyProperties(sysUser,sysUserDTO);
            this.addSysUser(sysUserDTO);
        }
        if (message.length() > 0) {
            throw new BDException(message.toString());
        }
    }

    public Boolean includeCustomInfo(Map<String, Integer> titleMap) {
        String[] field = {"*用户名", "*真实姓名", "*密码", "*邮箱", "*手机号", "性别", "出生日期"};
        for (int i = 0; i < field.length; i++) {
            Boolean isContain = titleMap.containsKey(field[i]);
            if (!isContain) {
                return false;
            }
        }
        return true;
    }

    @Override
    @Synchronized
    @Transactional(rollbackFor = Exception.class)
    public JSONObject importExcel(MultipartFile multipartFile) {
        // 初始化错误行信息list，用来记录导入失败的rowNum
        List<ExcelErrRowDTO> errRowDOs = new ArrayList<>();

        // 对excel是否为空进行check
        if (multipartFile.isEmpty()) {
            throw new BDException("导入失败，请选择文件！");
        }

        //设置excel参数
        ImportParams params = new ImportParams();
        params.setTitleRows(1);
        params.setHeadRows(1);
        List<SysUserImportDTO> sysUserList;
        List<SysUser> sysUsers = CollectionUtil.newArrayList();

        JSONObject result = new JSONObject();
        // 解析excel中的行，放到excel中
        try {
            // 解析excel
            sysUserList = ExcelImportUtil.importExcel(multipartFile.getInputStream(), SysUserImportDTO.class, params);
        } catch (Exception e) {
            throw new BDException("导入失败，文件内容解析错误！");
        }

        //校验 excel中的username是否重复
        if (sysUserList.size() > 0) {

            List<String> excelUsernames = sysUserList.stream()
                    .map(SysUserImportDTO::getUsername)
                    .collect(Collectors.toList()); // 获取excel中所有的username
            List<String> dbUsernames = this.getAllUsername();//获取系统中所有的username
            List<String> duplicateUsernames = new ArrayList<>(); // 存放存在重复的username，用于定位重复username的行

            if (dbUsernames.size() > 0 && excelUsernames.size() > 0) {
                dbUsernames.addAll(excelUsernames);//合并
                duplicateUsernames =ExcelUtils.getDuplicateElements(dbUsernames);//取出存在重复的username
            }

            // 部门map
            List<SysDept> deptList = sysDeptService.list();
            Map<String, Integer> deptMap = deptList.stream()
                    .collect(Collectors.toMap(SysDept::getDeptName, SysDept::getId, (v1, v2) -> v2));


            // 部门map
            List<SysRole> roleList = sysRoleService.list();
            Map<String, Integer> roleMap = roleList.stream()
                    .collect(Collectors.toMap(SysRole::getRoleName, SysRole::getId, (v1, v2) -> v2));


            int index = 1;
            for (SysUserImportDTO sysUserDTO : sysUserList) {
                index ++;
                // check
                StringBuilder stringBuilder = new StringBuilder();
                ExcelErrRowDTO excelErrRowDO= new ExcelErrRowDTO();

                // 参数校验
                stringBuilder.append(ValidatorUtils.validateExcel(sysUserDTO));

                // 检验username 是否重复
                if(duplicateUsernames.contains(sysUserDTO.getUsername())){
                    stringBuilder.append("用户名已经存在，请勿重复！");
                }
                // 设置deptId
                if(StringUtils.isNotEmpty(sysUserDTO.getDeptName())){
                    Integer deptId = deptMap.get(sysUserDTO.getDeptName());
                    if(deptId==null){
                        stringBuilder.append("部门:"+sysUserDTO.getDeptName()+",在系统中不存在");
                    }
                    sysUserDTO.setDeptId(deptId);
                }

                // 设置roleId
                if(StringUtils.isNotEmpty(sysUserDTO.getRoles())){
                    List<Integer> roleIds = new ArrayList<>();
                    boolean errFlag = false;
                    for (String s : sysUserDTO.getRoles().split(",")) {
                        Integer roleId = roleMap.get(s);
                        if(roleId==null){
                            stringBuilder.append("角色:"+s+",在系统中不存在！");
                            errFlag = true;
                            continue;
                        }
                        roleIds.add(roleId);
                    }
                    if(!errFlag){//角色没有错误 将角色保存到用户中
                        sysUserDTO.setRoleIds(roleIds);
                    }
                }

                // 将错误行信息保存到list
                String errMsg = stringBuilder.toString();
                if(StringUtils.isNotEmpty(errMsg)){
                    excelErrRowDO.setRowIndex(index);
                    excelErrRowDO.setErrMessage(errMsg);
                    errRowDOs.add(excelErrRowDO);
                    continue;
                }
                //保存
                SysUserDTO user = new SysUserDTO();
                BeanUtils.copyProperties(sysUserDTO,user);
                this.addSysUser(user);
            }
            // 导出错误行
            String errFileUrl = ExcelUtils.exportErrRows(errRowDOs,multipartFile,sysFileHisService);
            result.put("errFileUrl",errFileUrl);
        }
        return result;
    }

    private List<String> getAllUsername() {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.select("username");
        List<SysUser> userList = this.list();
        List<String> usernames = userList.stream().map(SysUser::getUsername).collect(Collectors.toList());
        return usernames;
    }
}






